import tkinter as tk
from PIL import Image, ImageDraw
import json

class MapViewer:
    def __init__(self, root, file_path, center_utm, scale, canvas_size):
        self.file_path = file_path
        self.center_utm = center_utm
        self.scale = scale
        self.canvas_size = canvas_size
        self.center_pixel = (canvas_size[0] // 2, canvas_size[1] // 2)
        self.offset = [0, 0]  # Offset for panning
        self.zoom_factor = 1.0  # Zoom factor

        # Initialize tkinter canvas
        self.canvas = tk.Canvas(root, width=canvas_size[0], height=canvas_size[1], bg="white")
        self.canvas.pack(fill=tk.BOTH, expand=True)
        self.canvas.bind("<ButtonPress-3>", self.start_pan)
        self.canvas.bind("<B3-Motion>", self.pan_map)
        self.canvas.bind("<MouseWheel>", self.zoom_map)
        self.canvas.bind("<Button-1>", self.on_click)  # Left-click binding to get UTM coordinates

        # Read and process data
        coords = self.read_coordinates()
        self.relative_coords = self.convert_to_relative(coords)

        # Draw initial map
        self.draw_map()

    def read_coordinates(self):
        """Read coordinates from a text file."""
        with open(self.file_path, 'r') as file:
            lines = file.readlines()
        coordinates = []
        for line in lines:
            if line.strip():
                points = line.strip().split(',')
                coordinates.append([(float(points[i]), float(points[i + 1])) for i in range(0, len(points), 2)])
        return coordinates

    def convert_to_relative(self, coords):
        """Convert UTM coordinates to relative pixel coordinates."""
        relative_coords = []
        for segment in coords:
            relative_segment = []
            for x, y in segment:
                rel_x = (x - self.center_utm[0]) / self.scale
                rel_y = (self.center_utm[1] - y) / self.scale  # Invert Y-axis for tkinter
                relative_segment.append((rel_x, rel_y))
            relative_coords.append(relative_segment)
        return relative_coords

    # def draw_map(self):
    #     """Draw the map on the canvas."""
    #     self.canvas.delete("all")  # Clear the canvas
    #     for segment in self.relative_coords:
    #         for i in range(len(segment) - 1):
    #             x1, y1 = segment[i]
    #             x2, y2 = segment[i + 1]
    #             self.canvas.create_line(
    #                 self.center_pixel[0] + x1 * self.zoom_factor + self.offset[0],
    #                 self.center_pixel[1] + y1 * self.zoom_factor + self.offset[1],
    #                 self.center_pixel[0] + x2 * self.zoom_factor + self.offset[0],
    #                 self.center_pixel[1] + y2 * self.zoom_factor + self.offset[1],
    #                 fill="black", width=4
    #             )

    def draw_map(self):
        """Draw the map on the canvas and add the car model."""
        self.canvas.delete("all")  # Clear the canvas
        # Draw the map's lines (same as before)
        for segment in self.relative_coords:
            for i in range(len(segment) - 1):
                x1, y1 = segment[i]
                x2, y2 = segment[i + 1]
                self.canvas.create_line(
                    self.center_pixel[0] + x1 * self.zoom_factor + self.offset[0],
                    self.center_pixel[1] + y1 * self.zoom_factor + self.offset[1],
                    self.center_pixel[0] + x2 * self.zoom_factor + self.offset[0],
                    self.center_pixel[1] + y2 * self.zoom_factor + self.offset[1],
                    fill="black", width=4
                )
        
        # Coordinates for the car model (in UTM)
        car_utm = (444460.68, 4427003.31)
        
        # Convert the car's UTM coordinates to relative pixel coordinates
        car_rel_x = (car_utm[0] - self.center_utm[0]) / self.scale
        car_rel_y = (self.center_utm[1] - car_utm[1]) / self.scale  # Invert Y-axis for tkinter
        
        # Define the size of the car model (rectangle)
        car_width = 30  # width of the rectangle in pixels
        car_height = 15  # height of the rectangle in pixels
        
        # Draw the car model as a rectangle on the canvas
        self.canvas.create_rectangle(
            self.center_pixel[0] + car_rel_x * self.zoom_factor + self.offset[0] - car_width / 2,
            self.center_pixel[1] + car_rel_y * self.zoom_factor + self.offset[1] - car_height / 2,
            self.center_pixel[0] + car_rel_x * self.zoom_factor + self.offset[0] + car_width / 2,
            self.center_pixel[1] + car_rel_y * self.zoom_factor + self.offset[1] + car_height / 2,
            fill="red", outline="black", width=2
        )


    def save_map_as_image(self):
        """Save the map as PNG and PGM files."""
        image = Image.new("RGB", self.canvas_size, "white")
        draw = ImageDraw.Draw(image)
        for segment in self.relative_coords:
            for i in range(len(segment) - 1):
                x1, y1 = segment[i]
                x2, y2 = segment[i + 1]
                draw.line(
                    [
                        (self.center_pixel[0] + x1 * self.zoom_factor + self.offset[0],
                         self.center_pixel[1] + y1 * self.zoom_factor + self.offset[1]),
                        (self.center_pixel[0] + x2 * self.zoom_factor + self.offset[0],
                         self.center_pixel[1] + y2 * self.zoom_factor + self.offset[1])
                    ],
                    fill="black", width=4
                )
        image.save("map.png")
        image.convert("L").save("map.pgm")

    def save_map_metadata(self):
        """Save map metadata as JSON."""
        metadata = {
            "map_size": self.canvas_size,
            "scale": self.scale,
            "center_utm": self.center_utm
        }
        with open("map.json", "w") as json_file:
            json.dump(metadata, json_file, indent=4)

    def start_pan(self, event):
        """Record the starting position for panning."""
        self.start_x = event.x
        self.start_y = event.y

    def pan_map(self, event):
        """Handle panning of the map."""
        dx = event.x - self.start_x
        dy = event.y - self.start_y
        self.offset[0] += dx
        self.offset[1] += dy
        self.start_x = event.x
        self.start_y = event.y
        self.draw_map()

    def zoom_map(self, event):
        """Handle zooming of the map."""
        factor = 1.1 if event.delta > 0 else 0.9
        self.zoom_factor *= factor
        self.draw_map()

    def on_click(self, event):
        """Handle click on the canvas and convert the pixel to UTM coordinates."""
        # Get the pixel coordinates where the user clicked
        pixel_x = event.x - self.center_pixel[0] - self.offset[0]
        pixel_y = event.y - self.center_pixel[1] - self.offset[1]

        # Convert pixel coordinates back to UTM coordinates
        utm_x = self.center_utm[0] + pixel_x * self.scale * self.zoom_factor
        utm_y = self.center_utm[1] - pixel_y * self.scale * self.zoom_factor  # Invert Y-axis for UTM

        # Print the UTM coordinates
        print(f"UTM Coordinates: ({utm_x:.2f}, {utm_y:.2f})")

def main():
    # Parameters
    file_path = r"C:\Users\17963\Desktop\ros_workspace\utm_coordinates.txt"  # Replace with your file name
    center_utm = (444431.969868, 4427046.542976)
    scale = 0.11  # 1 pixel = 0.05 meters
    canvas_size = (1000, 1000)  # Canvas size in pixels

    # Create Tkinter window
    root = tk.Tk()
    root.title("UTM Map Viewer")

    # Create MapViewer instance
    viewer = MapViewer(root, file_path, center_utm, scale, canvas_size)

    # Save map as image and metadata
    # viewer.save_map_as_image()
    # viewer.save_map_metadata()

    # Run Tkinter loop
    root.mainloop()

if __name__ == "__main__":
    main()
